import random
import string
from datetime import datetime, timedelta
from pprint import pprint

import exrex
from dateutil.relativedelta import relativedelta


def format_user_bill_data(data: dict) -> str:
    """Преобразуем дату из FSMContext в готовый текст"""

    first_name = data.get("first_name")
    last_name = data.get("last_name")
    house_num = data.get("house_num")
    street_name = data.get("street_name")
    city_name = data.get("city_name")
    postal_code = data.get("postal_code")

    txt = "Данные клиента\n"
    columns = ["Имя", "Фамилия", "Номер дома", "Улица", "Город", "Посткод"]
    values = [first_name, last_name, house_num, street_name, city_name, postal_code]

    for column, value in zip(columns, values):
        if value or value == "":
            txt += f"✅{column}: {value}\n"
        else:
            txt += f"{column}: \n"

    if not first_name:
        txt += "\nВведите имя ✏️"
    elif not last_name:
        txt += "\nВведите фамилию ✏️"
    elif not house_num and house_num != "":
        txt += "\nВведите номер дома, либо нажмите Пропустить ✏️"
    elif not street_name:
        txt += "\nВведите название улицы ✏️"
    elif not city_name:
        txt += "\nВведите название города ✏️"
    elif not postal_code:
        txt += "\nВведите посткод ✏️"

    return txt


def random_digit(length: int) -> str:
    letters = string.digits
    return "".join(random.choice(letters) for i in range(length))


def convert_float_to_str(fl: float, digits: int = 2) -> str:
    """
    Преобразуем float в строку без округления
    :param fl: Float число
    :param digits: Число знаков после точки
    :return: str
    """
    pattern = f"%.{digits}f"
    return pattern % fl


def format_date(
    my_date: datetime,
    day_format: str = "%-d",
    month_format: str = "%b.",
    year_format: str = "%Y",
):
    """Форматируем дату, подставляем суффикс"""

    date_suffixes = ["th", "st", "nd", "rd"]

    if day_format == "%-d":
        if my_date.day % 10 in [1, 2, 3] and datetime.day not in [11, 12, 13]:
            day_format = day_format + date_suffixes[my_date.day % 10]
        else:
            day_format = day_format + date_suffixes[0]
    return my_date.strftime(f"{day_format} {month_format} {year_format}")


def generate_uk_bill_data() -> dict:
    """
    Генерирует рандомные значения для UK платежки
    :return: Словарь со сгенерированными значениями
    """

    today = datetime.today()
    prev_month = today.replace(day=1) - timedelta(days=1)

    ### 1 страница

    account_number = exrex.getone(
        r"A-[0-9]{2}[A-Z]{2}[0-9][A-Z][0-9][A-Z]"
    )  # А-ЦЦББЦБЦБ
    excerpt_period_start, excerpt_period_end = generate_excerpt_period(
        prev_month
    )  # Период выписки
    excerpt_num = random_digit(8)  # Bill reference (номер выписки)
    qr_code_value = generate_qr_code_value(excerpt_num)
    gas_year_sum = random.randint(500, 999)  # Сумма за газ за год
    electricity_year_sum = random.randint(1000, 1500)  # Сумма за электричество за год
    excerpt_date = excerpt_period_end - timedelta(days=1)  # Дата выписки (11 Nov 2021)
    excerpt_forming_date = excerpt_period_end + timedelta(
        days=1
    )  # Дата формирования выписки
    previous_payment_sum = random.uniform(50.00, 99.99)  # Сумма предыдущего платежа
    previous_payment_date = prev_month.replace(
        day=random.randint(25, 29)
    )  # Дата предыдущего платежа, 25-29 число прошлого месяца

    electric_meter_number = random_digit(13)  # Номер электросчетчика
    gas_meter_number = random_digit(10)  # Номер газового счетчика
    end_of_cur_month = today.replace(day=29)  # 29 число текущего месяца

    ### 2 страница

    supply_number = random.randint(1, 9)  # Supply number на 2 странице
    supply_number_1 = random.randint(150, 950)
    supply_number_2 = random.randint(50, 250)

    gas_reading_start = float(
        random.randint(20000, 99999)
    )  # Показания электросчетчика на начало выписки
    electricity_reading_start = float(
        random.randint(20000, 99999)
    )  # Показания электросчетчика на начало выписки

    gas_reading_end = gas_reading_start + random.randint(
        50, 88
    )  # Показания электросчетчика на конец выписки
    electricity_reading_end = electricity_reading_start + random.randint(
        50, 299
    )  # Показания электросчетчика на конец выписки

    electricity_used = (
        electricity_reading_end - electricity_reading_start
    )  # Потрачено электроэнергии
    average_electricity_used = electricity_used / 29
    electricity_summ = (electricity_used * 17.37) / 100
    electricity_summ_with_charge = (
        electricity_summ + 6.05
    )  # Subtotal of charges before VAT
    electricity_vat = electricity_summ_with_charge * 0.05
    total_electricity_summ = (
        electricity_summ_with_charge + electricity_vat
    )  # Пишем на 1 страницу

    gas_used = gas_reading_end - gas_reading_start  # Потрачено газа
    average_gas_used = gas_used / 29
    gas_energy_used = (gas_used * 1.02264 * 39.4) / 3.6  # Energy used для газа
    gas_summ = (gas_energy_used * 3.1) / 100
    gas_summ_with_charge = gas_summ + 5.98  # Subtotal of charges before VAT
    gas_vat = gas_summ_with_charge * 0.05
    total_gas_summ = gas_summ_with_charge + gas_vat  # Пишем на 1 страницу

    gas_electricity_before_vat = (
        electricity_summ_with_charge + gas_summ_with_charge
    )  # Сумма за газ и электричество до VAT
    gas_electricity_vat = gas_electricity_before_vat * 0.05
    total_gas_electricity_summ = (
        gas_electricity_before_vat + gas_electricity_vat
    )  # Конечная сумма за электричество и газ

    price_guaranteed_until = excerpt_period_end + relativedelta(
        months=6
    )  # TODO Или тут excerpt_date?
    gas_estimated_annual_usage = random.randint(12000, 15000)
    electricity_estimated_annual_usage = float(random.randint(5000, 7000))

    return {
        "account_number": account_number,
        "qr_code_value": qr_code_value,
        "excerpt_period_start": format_date(excerpt_period_start),
        "excerpt_period_start_full_month": format_date(excerpt_period_start, month_format="%B"),
        "excerpt_period_end": format_date(excerpt_period_end),
        "excerpt_period_end_full_month": format_date(excerpt_period_end, month_format="%B"),
        "excerpt_num": excerpt_num,
        "gas_year_sum": convert_float_to_str(gas_year_sum),
        "electricity_year_sum": convert_float_to_str(electricity_year_sum),
        "excerpt_date": format_date(excerpt_date),
        "excerpt_forming_date": format_date(excerpt_forming_date),
        "previous_payment_sum": convert_float_to_str(previous_payment_sum, 2),
        "previous_payment_date": format_date(previous_payment_date),
        "electric_meter_number": electric_meter_number,
        "gas_meter_number": gas_meter_number,
        "end_of_cur_month": format_date(end_of_cur_month, month_format="%B"),
        "supply_number": str(supply_number),
        "supply_number1": str(supply_number_1),
        "supply_number2": str(supply_number_2),
        "gas_reading_start": convert_float_to_str(gas_reading_start, 1),
        "electricity_reading_start": convert_float_to_str(electricity_reading_start, 1),
        "gas_reading_end": convert_float_to_str(gas_reading_end, 1),
        "electricity_reading_end": convert_float_to_str(electricity_reading_end, 1),
        "electricity_used": convert_float_to_str(electricity_used, 1),
        "average_electricity_used": convert_float_to_str(average_electricity_used),
        "electricity_summ": convert_float_to_str(electricity_summ),
        "electricity_summ_with_charge": convert_float_to_str(
            electricity_summ_with_charge
        ),
        "electricity_vat": convert_float_to_str(electricity_vat),
        "total_electricity_summ": convert_float_to_str(total_electricity_summ),
        "gas_used": convert_float_to_str(gas_used, 1),
        "average_gas_used": convert_float_to_str(average_gas_used),
        "gas_energy_used": convert_float_to_str(gas_energy_used),
        "gas_summ": convert_float_to_str(gas_summ),
        "gas_summ_with_charge": convert_float_to_str(gas_summ_with_charge),
        "gas_vat": convert_float_to_str(gas_vat),
        "total_gas_summ": convert_float_to_str(total_gas_summ),
        "gas_electricity_before_vat": convert_float_to_str(gas_electricity_before_vat),
        "gas_electricity_vat": convert_float_to_str(gas_electricity_vat),
        "total_gas_electricity_summ": convert_float_to_str(total_gas_electricity_summ),
        "price_guaranteed_until": format_date(
            price_guaranteed_until, month_format="%b"
        ),
        "gas_estimated_annual_usage": str(gas_estimated_annual_usage),
        "electricity_estimated_annual_usage": str(electricity_estimated_annual_usage),
    }


def generate_excerpt_period(prev_month: datetime) -> tuple[datetime, datetime]:
    """
    Период выписки 14th Oct. 2021 - 12th Nov 2021
    2-14 число прошлого месяца + 29 дней
    """

    start = prev_month.replace(day=random.randint(2, 14))
    end = start + timedelta(days=29)

    return start, end


def generate_qr_code_value(excerpt_num: str) -> str:
    """Генерируем qr код на основе номера выписки"""

    value = "1,01,786775,24505033,E8C9BC3ABE1BCB"
    code_pattern = "[A-Z][1-9][A-Z][1-9][A-Z]{2}[1-9][A-Z]{3}[1-9][A-Z]{3}"

    return value.replace("24505033", excerpt_num).replace(
        "E8C9BC3ABE1BCB", exrex.getone(code_pattern)
    )


if __name__ == "__main__":
    pprint(generate_uk_bill_data())
